﻿#region License - Microsoft Public License - from PG Software Solutions Inc.
/***********************************************************************************
 * This software is copyright © 2012 by PG Software Solutions Inc. and licensed under
 * the Microsoft Public License (http://cudafytuningtutorial.codeplex.com/license).
 * 
 * Author:			Pieter Geerkens
 * Organization:	PG Software Solutions Inc.
 * *********************************************************************************/
#endregion
using System;
using System.Collections.Generic;
using System.Linq.Expressions;

using Irony.Parsing;
using PGSoftwareSolutionsInc.PGIrony;

	// best viewed with: Tab Size = 3; Indent Size = 3; Keep Tabs = On.
namespace PGSoftwareSolutionsInc.Util.PlayWaveLib {
	[Language("StatementList", "1.0", "Simple Statement-List grammar example")]
	public class AstGrammarTest : PGIrony.Grammar<MyAstContext> {
		public AstGrammarTest() : base(false,LanguageFlags.CreateAst) {
         GrammarComments = 
				@"Simple Statement-List grammar example, illustrating use of PGIrony library.";

			#region 1-Terminals - in PascalCase
				var Id			= new IdentifierTerminal("Identifier");
				var IntNum		= new NumberLiteral("",	NumberOptions.IntOnly);
				var RealNum		= new NumberLiteral("",	NumberOptions.None);

				var Assignment	= ToTerm(":=");
				var Terminator	= ToTerm(";");
				var OpenParen	= ToTerm("(");
				var CloseParen	= ToTerm(")");
				var Comment		= new RegexBasedTerminal("Comment",		@"//.*\n");

				MarkPunctuation(Terminator, Assignment, OpenParen, CloseParen, Comment);
			#endregion

			#region 2-NonTerminals - in camelCase
				var binaryOp	= new PGIrony.TransientNonTerminal("BinOp");
				var unaryOp		= new PGIrony.TransientNonTerminal("UnaryOp");
				var numeric		= new PGIrony.TransientNonTerminal("Numeric");
				var expr			= new TypedNonTerminal<ExpressionAstNode>();
				var stmt			= new TypedNonTerminal<StatementAstNode>();
				var stmtList	= new TypedNonTerminal<StatementListAstNode>();
			#endregion

			#region 3-Rules
				Root				= stmtList
									;
				stmtList.Rule	= MakePlusRule(stmtList, stmt)
									; 
				stmt.Rule		= Id + Assignment + expr + Terminator
									| Comment
									;
				expr.Rule		= numeric
									| Id
									| OpenParen + expr + CloseParen
									| expr + binaryOp + expr
									| unaryOp + expr + ReduceHere()
									;
				unaryOp.Rule	= ToTerm("+") | "-" 
									;
				binaryOp.Rule	= ToTerm("*") | "/" | unaryOp
									;
				numeric.Rule	= IntNum
									| RealNum
									;
				stmt.ErrorRule = SyntaxError + Terminator
									;

				RegisterBracePair("(", ")");

				// operator associativites in decreasing order of precedence
				RegisterOperators(20, Associativity.Left, "*", "/");
				RegisterOperators(10, Associativity.Left, "+", "-");
			#endregion
		}
		/// <summary>Provide MyGrammar with appropriate AstContext.</summary>
		/// <param name="language"></param>
		/// <returns></returns>
		protected override MyAstContext GetContext(LanguageData language) {
			return new MyAstContext(language);
		}
	}

	public class MyAstContext : PGIrony.AstContext {
		public MyAstContext(LanguageData language) : base(language) {}
	}

	public class TypedNonTerminal<TAstNode> : TypedNonTerminal<MyAstContext,TAstNode> 
	where TAstNode : AstNode<MyAstContext>{}

	// NB: Node description in Grammar Explorer tree-view automatically 
	// generated by stripping "AstNode" from GetType().Name.
	public class ExpressionAstNode		: AstNode<MyAstContext> {}
	public class StatementAstNode			: AstNode<MyAstContext> {}
	public class StatementListAstNode	: ListNode<MyAstContext> {}
}
